/** \file    optic_flow.h
  * \brief   Makes transform more precise by using direct pixels-based motion estimation method.
  * \date    2002, 2003
  * \author  Fedor Chelnokov
  * \version $Header: /home/cscom1r4/cvsroot/cs/include/imglib/optic_flow.h,v 1.2 2004/07/21 19:51:27 cscom1r4 Exp $
  */

#ifndef _optic_flow_h_
#define _optic_flow_h_

#include "bitmap.h"
#include "imageclass_decl.h"
#include "color.h"
#include "segm/MotionParams.h"

namespace mswin { class timing_tree; }

namespace img {

template <class T> class transform_solver;

template <class T>
class optic_flow {

	struct solution {
		T transform, amendment;
		double discrepancy;

		bool discrepancy_found() const
			{ return discrepancy >= 0; }
		bool replace_if_better(const solution & s) {
			assert(discrepancy_found() && s.discrepancy_found());
			if (s.discrepancy < discrepancy) {
				*this = s;
				return true;
			}
			else
				return false;
		}
	};

public:
	optic_flow();
	~optic_flow();

	///\param transform here is very rough approximation of real transformations
	///   that will be encountered during optimize
	///\return false if preparation failed (due to small mask or bad transform)
	bool prepare(const T & transform, 
		const float_image & frame0, const bitmap & mask0, 
		TransformClass model = TRANSFORM_AFFINE, bool point2point = false);
	///preparation without transform prediction
	bool prepare(const float_image & frame0, const bitmap & mask0, 
		TransformClass model = TRANSFORM_AFFINE, bool point2point = false) 
	{
		T transform;
		transform.identity();
		return prepare(transform, frame0, mask0, model, point2point);
	}
	unsigned mask_size() const
		{ return _frame0_data.size(); }

	double discrepancy(const float_image & frame1, const mswin::timing_tree * tt = 0);
	void optimize(const float_image & frame1, unsigned iterations, 
		const mswin::timing_tree * tt = 0);

	void transform(const T & t, double discrepancy = -1);
	const T & transform() const
		{ return _solution.transform; }
	const T & amendment() const
		{ return _solution.amendment; }
	double discrepancy() const
		{ return _solution.discrepancy; }

public:
	struct pixel0 {
		pixel0() {}
		pixel0(const float_color & ii, size_t x, size_t y) : I(ii), p(x, y) {}
		float_color I;
		float squared_Ir;
		size_point p;
	};

private:
	void new_p2l_solver(TransformClass model);
	void new_p2p_solver(TransformClass model);
	void optimize_single_solver(const float_image & frame1, unsigned iterations, 
		const mswin::timing_tree * tt = 0);

private:
	transform_solver<T> * _solver;
	transform_solver<T> * _extra_solver;
	unsigned _w, _h;
	std::vector<pixel0>	_frame0_data; ///< serialization of pixels under mask
	solution _solution;
};

} //namespace img

#endif //_optic_flow_h_
